home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / program / ixemlsrc.lha / ixemul / utils / ixtimezone.c < prev    next >
C/C++ Source or Header  |  1995-12-23  |  8KB  |  307 lines

  1. /*
  2.  *  Written by Hans Verkuil (hans@wyst.hobby.nl)
  3.  *
  4.  *  battclock.resource patch idea was shamelessly stolen from the unixclock
  5.  *  utility written by Geert Uytterhoeven. unixclock is available on Aminet.
  6.  */
  7.  
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <time.h>
  11.  
  12. #include <ixemul.h>
  13. #include <exec/memory.h>
  14. #include <clib/exec_protos.h>
  15. #include <dos/var.h>
  16.  
  17. #include <sys/time.h>
  18.  
  19. #define LVOReadBattClock    (-12)
  20. #define LVOWriteBattClock    (-18)
  21.  
  22. /* Flags. Currently only bit 0 is used to tell whether Daylight Saving Time
  23.    is in effect or not. However, ixtimezone only sets this flag, but it doesn't
  24.    test it. And neither does ixemul.library. In fact, the library completely
  25.    ignores the flag field. */
  26.  
  27. #define DST_ON    0x01
  28.  
  29. typedef struct
  30. {
  31.   long          offset;
  32.   unsigned char flags;
  33. } ixtime;
  34.  
  35. struct Library *BattClockBase;
  36.  
  37. char VERSION[] = "\000$VER: ixtimezone 1.0 (10.11.95)";
  38.  
  39. /* battclock.resource patch code */
  40. asm("
  41.     .text
  42.     .globl _NewReadBattClock
  43.     .globl _NewWriteBattClock
  44.     .globl _OldReadBattClock
  45.     .globl _OldWriteBattClock
  46.     .globl _GMTOffset
  47.     .globl _EndOfPatch
  48.  
  49. _NewReadBattClock:
  50.     .int    0x207a0014, 0x4e9090ba, 0x00164e75
  51.  
  52. /*    Since the GNU assembler is currently unable to properly compile
  53.     PC-relative code, I'm using the hex-code directly. As soon as the
  54.     assembler can handle PC-relative code, the line above should be
  55.     replaced by:
  56.  
  57.     move.l        _OldReadBattClock(pc),a0
  58.     jsr        (a0)
  59.     sub.l        _GMTOffset(pc),d0
  60.     rts
  61. */
  62.  
  63. _NewWriteBattClock:
  64.     .int    0xd0ba0010, 0x207a0008
  65.     .short    0x4ed0
  66.  
  67. /*    Since the GNU assembler is currently unable to properly compile
  68.     PC-relative code, I'm using the hex-code directly. As soon as the
  69.     assembler can handle PC-relative code, the line above should be
  70.     replaced by:
  71.  
  72.     add.l        _GMTOffset(pc),d0
  73.     move.l        _OldWriteBattClock(pc),a0
  74.     jmp        (a0)
  75. */
  76.  
  77. _OldReadBattClock:
  78.     .int        0
  79. _OldWriteBattClock:
  80.     .int        0
  81. _GMTOffset:
  82.     .int        0
  83. _EndOfPatch:
  84. ");
  85.  
  86. extern char NewReadBattClock;
  87. extern char NewWriteBattClock;
  88. extern char OldReadBattClock;
  89. extern char OldWriteBattClock;
  90. extern long GMTOffset; 
  91. extern long EndOfPatch;
  92. extern struct ixemul_base *ixemulbase;
  93.  
  94. static ixtime *read_ixtime(void)
  95. {
  96.   static ixtime t;
  97.   char buf[10];
  98.   
  99.   /*
  100.    * Read the GMT offset. This environment variable is 5 bytes long. The
  101.    * first 4 form a long that contains the offset in seconds and the fifth
  102.    * byte contains flags.
  103.    */
  104.   if (GetVar("IXGMTOFFSET", buf, 6, GVF_BINARY_VAR) == 5 && IoErr() == 5)
  105.   {
  106.     memcpy(&t.offset, buf, 4);
  107.     t.flags = buf[4];
  108.     return &t;
  109.   }
  110.   return NULL;
  111. }
  112.  
  113. static void create_ixtime(ixtime *t, char *pathname)
  114. {
  115.   FILE *f = fopen(pathname, "w");
  116.   
  117.   if (f)
  118.   {
  119.     fwrite(t, 5, 1, f);
  120.     fclose(f);
  121.   }
  122. }
  123.  
  124. static void write_ixtime(ixtime *t, int write_also_to_envarc)
  125. {
  126.   ix_set_gmt_offset(t->offset);
  127.   create_ixtime(t, "/ENV/IXGMTOFFSET");
  128.   if (write_also_to_envarc)
  129.     create_ixtime(t, "/ENVARC/IXGMTOFFSET");
  130. }
  131.  
  132. static void set_clock(long offset)
  133. {
  134.   struct timeval tv;
  135.   
  136.   gettimeofday(&tv, NULL);
  137.   tv.tv_sec += offset;
  138.   settimeofday(&tv, NULL);
  139. }
  140.  
  141. static void reset_clock(void)
  142. {
  143.   struct timeval tv;
  144.   
  145.   tv.tv_usec = 0;
  146.   tv.tv_sec = ReadBattClock();
  147.   tv.tv_sec += (8*365+2) * 24 * 3600 + ix_get_gmt_offset();
  148.   settimeofday(&tv, NULL);
  149. }
  150.  
  151. static long *get_function_addr(void)
  152. {
  153.   return *((long **)((char *)BattClockBase + LVOReadBattClock + 2));
  154. }
  155.  
  156. static void patch_batt_resource(long offset)
  157. {
  158.   char *mem;
  159.   long size = (long)&EndOfPatch - (long)&NewReadBattClock;
  160.   long mem_offset;
  161.   long *oldread, *oldwrite, *gmt;
  162.  
  163.   BattClockBase = (struct Library *)OpenResource("battclock.resource");
  164.   if (*(gmt = get_function_addr()) == 0x207a0014)
  165.   {
  166.     printf("battclock.resource was already patched.\n");
  167.     gmt = (long *)(((char *)&GMTOffset) + (long)((char *)gmt - &NewReadBattClock));
  168.     if (*gmt != offset)
  169.     {
  170.       *gmt = offset;
  171.       reset_clock();
  172.     }
  173.     return;  /* already patched */
  174.   }
  175.   GMTOffset = offset;
  176.   mem = AllocMem(size, MEMF_PUBLIC);
  177.   mem_offset = mem - &NewReadBattClock;
  178.   memcpy(mem, &NewReadBattClock, size);
  179.   CacheClearE(mem, size, CACRF_ClearI);  /* clear instruction cache */
  180.   oldread = (long *)(&OldReadBattClock + mem_offset);
  181.   oldwrite = (long *)(&OldWriteBattClock + mem_offset);
  182.   Disable();
  183.   *oldread = (long)SetFunction(BattClockBase, LVOReadBattClock, (void *)(&NewReadBattClock + mem_offset));
  184.   *oldwrite = (long)SetFunction(BattClockBase, LVOWriteBattClock, (void *)(&NewWriteBattClock + mem_offset));
  185.   Enable();
  186.   reset_clock();
  187.   printf("patched battclock.resource.\n");
  188. }
  189.  
  190. static void remove_patch(void)
  191. {
  192.   long *p, mem_offset, *oldread, *oldwrite;
  193.   long size = (long)&EndOfPatch - (long)&NewReadBattClock;
  194.  
  195.   BattClockBase = (struct Library *)OpenResource("battclock.resource");
  196.   if (*(p = get_function_addr()) != 0x207a0014)
  197.   {
  198.     printf("battclock.resource wasn't patched.\n");
  199.     exit(0);  /* not patched */
  200.   }
  201.   mem_offset = (char *)p - &NewReadBattClock;
  202.   oldread = (long *)(&OldReadBattClock + mem_offset);
  203.   oldwrite = (long *)(&OldWriteBattClock + mem_offset);
  204.   Disable();
  205.   SetFunction(BattClockBase, LVOReadBattClock, (void *)*oldread);
  206.   SetFunction(BattClockBase, LVOWriteBattClock, (void *)*oldwrite);
  207.   Enable();
  208.   FreeMem(p, size);
  209.   reset_clock();
  210.   printf("removed battclock.resource patch.\n");
  211.   exit(0);
  212. }
  213.  
  214. static void test(void)
  215. {
  216.   time_t t;
  217.   
  218.   time(&t);
  219.   printf("GMT:   %s", asctime(gmtime(&t)));
  220.   printf("Local: %s", asctime(localtime(&t)));
  221.   exit(0);
  222. }
  223.  
  224. static void usage(void)
  225. {
  226.   fprintf(stderr, "Usage: ixtimezone <option>
  227. Where <option> is one of:
  228.  
  229. -test        Show GMT and localtime
  230. -get-offset    Get GMT offset and patch ixemul.library
  231. -check-dst    As -get-offset, but also automatically adjust the Amiga
  232.         time if Daylight Saving Time has gone in effect (or vice
  233.         versa)
  234. -patch-resource    As -get-offset, but also patch the battclock.resource
  235. -remove-patch    Remove the battclock.resource patch\n");
  236.   exit(1);
  237. }
  238.  
  239. int main(int argc, char **argv)
  240. {
  241.   struct tm *local_tm, *gmt_tm;
  242.   int local_hms, gmt_hms;
  243.   time_t t, local_t, gmt_t;
  244.   ixtime *old, new;
  245.   int set_the_clock = 0, patch_resource = 0;
  246.   int write_to_envarc = 0;
  247.  
  248.   if (ixemulbase->ix_lib.lib_Version < 42)
  249.   {
  250.     fprintf(stderr, "ixtimezone requires ixemul.library version 42 or higher.\n");
  251.     exit(1);
  252.   }
  253.   if (argc != 2)
  254.     usage();
  255.  
  256.   if (!strcmp(argv[1], "-test"))
  257.     test();
  258.   else if (!strcmp(argv[1], "-check-dst"))
  259.     set_the_clock = 1;
  260.   else if (!strcmp(argv[1], "-patch-resource"))
  261.     patch_resource = 1;
  262.   else if (!strcmp(argv[1], "-remove-patch"))
  263.     remove_patch();
  264.   else if (strcmp(argv[1], "-get-offset"))
  265.     usage();
  266.  
  267.   /*
  268.    * Get current time, both GMT and local.  
  269.    * We don't care if these values are correct or not, we are only interested
  270.    * in the difference between the two.
  271.    */
  272.  
  273.   time(&t);
  274.   gmt_tm = gmtime(&t);
  275.   gmt_hms = gmt_tm->tm_hour * 3600 + gmt_tm->tm_min * 60 + gmt_tm->tm_sec;
  276.   local_tm = localtime(&t);
  277.   local_hms = local_tm->tm_hour * 3600 + local_tm->tm_min * 60 + local_tm->tm_sec;
  278.   new.flags = (local_tm->tm_isdst ? DST_ON : 0);
  279.   new.offset = 0;
  280.   if (gmt_hms != local_hms)
  281.   {
  282.     /* They are not the same. So compute the difference between them */
  283.  
  284.     local_tm->tm_isdst = 0;     /* don't let these values influence the result! */
  285.     local_tm->tm_zone = NULL;
  286.     local_tm->tm_gmtoff = 0;
  287.     local_t = mktime(local_tm);
  288.     gmt_tm = gmtime(&t);
  289.     gmt_tm->tm_isdst = 0;
  290.     gmt_tm->tm_zone = NULL;
  291.     gmt_tm->tm_gmtoff = 0;
  292.     gmt_t = mktime(gmt_tm);
  293.     new.offset = gmt_t - local_t;     /* obtain the difference */
  294.   }
  295.  
  296.   old = read_ixtime();
  297.   if (old == NULL || old->offset != new.offset)
  298.   {
  299.     write_to_envarc = 1;
  300.     if (set_the_clock && old)
  301.       set_clock(old->offset - new.offset);
  302.   }
  303.   write_ixtime(&new, write_to_envarc);
  304.   if (patch_resource)
  305.     patch_batt_resource(new.offset);
  306. }
  307.